package 反射;

import org.junit.Test;

import java.lang.reflect.*;
import java.util.Scanner;

/**
 *                 动态语言(运行时结构可变:PHP、Python、JavaScript、C#)
 *                 静态语言(运行时结构不可变:Java、C、C++)
 * 反射(Reflection):动态语言的关键(使Java变为准动态语言),
 *                  允许程序在执行期借助Reflection API获取任何类的内部信息,
 *                  并能操作任意对象的内部属性及方法
 * 反射和面向对象的封装性的矛盾：封装(按建议的路用钥匙走进门),反射()
 * new和反射创建对象的方式：当运行时不确定new谁时使用反射创建对象(接收客户端的未知指令,通过反射调用指令对应的方法)
 *                      当编译时确定new对象时用正常的创建对象。
 * java.long.Class:1.类的加载：源程序->编译器(javac.exe)->字节码文件(.class)->(java.exe)->解释加载到内存中
 *                           此时加载到内存中的类被称为运行时类=Class的一个实例
 *                 2.Class实例的四种获取方式：调用运行时类的属性(Emp.class)
 *                                        运行时类的对象(new Emp().getClass())
 *                                   (常用)Class的静态方法(Class.formName(String classPath))
 *                                 (仅了解)类的加载器(类名.class.getClassLoader().loadClass(String classPath))
 *                                   注：Class类的实例是唯一的
 *                 3.类的加载过程：类的加载(创建.class)+类的链接(二进制合并到JRE)+类的初始化(JVM进行初始化)
 *
 */

public class ReflectDemo {
    @Test
    public void test(){
        try {
            //1.获取实例化的类
            Class clazz=Emp.class;
            //2.newInstance()设置类的构造器参数,获取运行时类,需与原类内的构造器匹配
            Constructor con = clazz.getConstructor(String.class,int.class,String.class,double.class);
            Object o = con.newInstance("喵喵", 11,"22",33.0);//对象
            //3.设置可以获取私有的属性方法的权限
            con.setAccessible(true);
            //4.通过反射设置运行时类的指定属性
            Field name = clazz.getDeclaredField("name");
            name.set(o,"喵喵喵");//设置属性
            //5.通过反射调用运行时类的指定方法
            Method toString = clazz.getDeclaredMethod("toString");
            toString.invoke(o);//调用方法
            //输出结果
            Emp emp=(Emp)o;
            System.out.println(emp.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Scanner scanner = new Scanner(System.in);
        String i = scanner.nextLine();
        //1.Class.forName(String str)获取输入字符串的运行时类
        Class aClass = Class.forName(i);
        //2.getMethod(String str)获取运行时类的指定方法名
        Method method =  aClass.getMethod("nextInt");
        //3.getMethods()获取运行时类的所有public方法名(包括父类)
        Method[] mmethods = aClass.getMethods();
        Method[] mmethodss = aClass.getDeclaredMethods();//不包括父类的方法
        for (Method m:mmethods){
            //获取方法声明的注解
            m.getAnnotations();
            //获取方法的权限修饰符
            m.getModifiers();
            //获取方法的返回值类型
            m.getReturnType();
            //获取方法名
            m.getName();
            //获取形参列表
            m.getParameterTypes();
            //获取抛出的异常类型
            m.getExceptionTypes();
        }
        //4.newInstance()创建运行时类下的的实例对象
        Object o = aClass.newInstance();
        //5.getConstructor(String.class)通过运行时类调用构造器
        Constructor constructor = aClass.getConstructor(String.class);
        //getConstructors()获取当前运行时类中声明为public的构造器
        aClass.getConstructors();
        //getDeclaredConstructors()获取当前运行时类中的所有构造器
        aClass.getDeclaredConstructors();
        //6.constructor.newInstance(String);通过构造器进行实例化
        constructor.newInstance("");
        //7.invoke(String message,int sum)执行指定方法和执行次数
        method.invoke("",5);
        //8.setAccessible(true)设置权限可以访问私有属性
        method.setAccessible(true);
        //10.getMethods()获取运行时类的所有public属性(包括父类的public属性)
        Field[] fields = aClass.getFields();
        //11.getDeclaredFields()获取运行时类的所有属性(不包括父类的属性)
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f:fields){
            //获取属性的权限修饰符的常量值
            f.getModifiers();
            //获取属性的数据类型
            f.getType();
            //获取属性名
            f.getName();
        }
        //12.getGenericSuperclass()获取运行时类的带泛型的父类的泛型
        Type superclass = aClass.getGenericSuperclass();
        ParameterizedType parameterizedType=(ParameterizedType) superclass;
        //13.获取泛型的类型
        Type[] arguments = parameterizedType.getActualTypeArguments();
        //14.获取运行时类实现的接口(动态代理使用)
        aClass.getInterfaces();
        //获取运行时类实现的父类的接口
        aClass.getSuperclass().getInterfaces();
        //15.获取运行时类实现的包
        aClass.getPackage();
        //15.获取运行时类实现声明的注解
        aClass.getAnnotations();
    }
}
